/**
  ******************************************************************************
  * File Name          : proddb.c
  * Description        : 产量数据库维护
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "bsp.h"
#include "tskcfg.h"
#include "produp.h"
#include "ff.h"
#include "sdiobsp.h"
#include <string.h>

static FATFS fs;
static FIL   file;

static const char fs_lable[]  = "";
static const char file_name[] = "p202502.pdb";

/* 初始化数据库文件头, 此函数必须在文件打开的情况下调用 */
static uint8_t file_header_init(FIL *fp, Prod_DBFileHeaderStru *pfhd)
{
  UINT act;
  FRESULT res;

  FsDbgLog("%s\r\n", __FUNCTION__);

  if((fp == NULL) || (pfhd == NULL)){
    return 1;
  }

  /* 退回至文件头 */
  res = f_rewind(fp);
  if(res || (f_tell(fp) != 0)){
    FsErrLog("f_rewind res:%d, fp:%d\r\n", res, f_tell(fp));
    return 2;
  }

  pfhd->header = PROD_DBFILE_HEADER;
  pfhd->besent = 0;
  pfhd->allitm = 0;
  pfhd->xorchk = pfhd->besent ^ pfhd->allitm;

  res = f_write(fp, pfhd, sizeof(Prod_DBFileHeaderStru), &act);
  if(res || (act != sizeof(Prod_DBFileHeaderStru))){
    FsErrLog("f_write res:%d, btw:%d, bw:%d\r\n", res, sizeof(Prod_DBFileHeaderStru), act);
    return 3;
  }

  return 0;
}

uint8_t sd_detect_mount(void)
{
  FRESULT res;
  
  if((sd_card_detect() == 0) && (fs.fs_type == 0))  /* 检测到已插卡且未挂载 执行mount */
  {
    res = f_mount(&fs, fs_lable, 1);
    if(res){
      FsErrLog("f_mount res:%d\r\n", res);
    }
  }
  else if((sd_card_detect() != 0) && (fs.fs_type != 0)) /* 检测到未插卡且已挂载 执行unmount */
  {
    res = f_unmount(fs_lable);
    if(res){
      FsErrLog("f_unmount res:%d\r\n", res);
    }
  }
  
  if(fs.fs_type == 0)
  {
    return 0;  /* 未挂载 */
  }
  else
  {
    return 1;  /* 已挂载 */
  }
}

uint8_t proddb_save(Prod_DataBaseStru *produp, uint8_t *isrtdata)
{
  uint8_t ret = 0;
  FRESULT res = FR_NO_FILE;
  UINT act;
  FSIZE_t ofs;
  Prod_DBFileHeaderStru fhd;

  FsDbgLog("%s\r\n", __FUNCTION__);

  res = f_open(&file, file_name, (FA_OPEN_ALWAYS | FA_READ | FA_WRITE));
  if(res){
    FsErrLog("f_open res:%d\r\n", res);
    return 1;
  }

  res = f_read(&file, &fhd, sizeof(fhd), &act);
  if(res){
    FsErrLog("f_read res:%d\r\n", res);
    ret = 2;
    goto close_file1;
  }

  /* 文件头不存在或者有误 重新创建 */
  if((act < sizeof(fhd)) || (fhd.header != PROD_DBFILE_HEADER) || ((fhd.besent ^ fhd.allitm) != fhd.xorchk))
  {
    res = file_header_init(&file, &fhd);
    if(res){
      FsErrLog("file_header_init res:%d\r\n", res);
      ret = 3;
      goto close_file1;
    }
  }

  if((fhd.allitm == fhd.besent) && (isrtdata != NULL)){
    *isrtdata = 1;
  }else{
    *isrtdata = 0;
  }

  /* 移动文件指针到"文件头"指定位置 */
  ofs = sizeof(fhd) + (fhd.allitm * sizeof(Prod_DataBaseStru));
  res = f_lseek(&file, ofs);
  if(res || (f_tell(&file) != ofs)){
    FsErrLog("f_lseek res:%d, fp:%d, ofs:%d\r\n", res, f_tell(&file), ofs);
    ret = 4;
    goto close_file1;
  }

  /* 在新指针处截断文件 */
  res = f_truncate(&file);
  if(res){
    FsErrLog("f_truncate res:%d\r\n", res);
    ret = 5;
    goto close_file1;
  }

  produp->header = PROD_DATABASE_HEADER;
  produp->posi   = PROD_DATABASE_POSI;
  produp->serial = fhd.allitm;

  /* 写入新数据 */
  res = f_write(&file, produp, sizeof(Prod_DataBaseStru), &act);
  if(res || (act != sizeof(Prod_DataBaseStru))){
    FsErrLog("f_write res:%d, btw:%d, bw:%d\r\n", res, sizeof(Prod_DataBaseStru), act);
    ret = 6;
    goto close_file1;
  }

  /* 退回至文件头 */
  res = f_rewind(&file);
  if(res || (f_tell(&file) != 0)){
    FsErrLog("f_rewind res:%d, fp:%d\r\n", res, f_tell(&file));
    ret = 7;
    goto close_file1;
  }

  fhd.allitm++;
  fhd.xorchk = fhd.besent ^ fhd.allitm;

  /* 回写更新文件头 */
  res = f_write(&file, &fhd, sizeof(fhd), &act);
  if(res || (act != sizeof(fhd))){
    FsErrLog("f_write res:%d, btw:%d, bw:%d\r\n", res, sizeof(fhd), act);
    ret = 8;
    goto close_file1;
  }

close_file1:
  f_close(&file);

  return ret;
}

uint8_t proddb_check(Prod_DataBaseStru *produp, uint8_t *ishsdata)
{
  uint8_t ret = 0;
  FRESULT res = FR_NO_FILE;
  UINT act;
  FSIZE_t ofs;
  Prod_DBFileHeaderStru fhd;

  FsDbgLog("%s\r\n", __FUNCTION__);

  if((produp == NULL) || (ishsdata == NULL)){
    return 1;
  }

  *ishsdata = 0;

  /* 以只读方式打开文件 若文件不存在或打开失败则退出 */
  res = f_open(&file, file_name, (FA_OPEN_EXISTING | FA_READ));
  if(res == FR_NO_FILE){
    FsDbgLog("f_open no file\r\n");
    return 2;
  }else if(res != FR_OK){
    FsErrLog("f_open res:%d\r\n", res);
    return 3;
  }

  /* 读取文件头 */
  res = f_read(&file, &fhd, sizeof(fhd), &act);
  if(res){
    FsErrLog("f_read res:%d\r\n", res);
    ret = 4;
    goto close_file2;
  }

  /* 文件头不存在或者有误 直接返回 */
  if((act < sizeof(fhd)) || (fhd.header != PROD_DBFILE_HEADER) || ((fhd.besent ^ fhd.allitm) != fhd.xorchk)){
    ret = 5;
    goto close_file2;
  }

  /* 如果待发大于全部 直接返回 */
  if(fhd.besent > fhd.allitm){
    ret = 6;
    goto close_file2;
  }

  /* 无数据可发 */
  if(fhd.besent == fhd.allitm){
    ret = 7;
    goto close_file2;
  }

  /* 移动文件指针到"待发"指定位置 */
  ofs = sizeof(fhd) + (fhd.besent * sizeof(Prod_DataBaseStru));
  res = f_lseek(&file, ofs);
  if(res || (f_tell(&file) != ofs)){
    FsErrLog("f_lseek res:%d, fp:%d, ofs:%d\r\n", res, f_tell(&file), ofs);
    ret = 8;
    goto close_file2;
  }

  res = f_read(&file, produp, sizeof(Prod_DataBaseStru), &act);
  if(res || (act < sizeof(Prod_DataBaseStru))){
    FsErrLog("f_read res:%d btr:%d, br:%d\r\n", res, sizeof(Prod_DataBaseStru), act);
    ret = 9;
    goto close_file2;
  }
  
  *ishsdata = 1;
  
close_file2:
  f_close(&file);

  return ret;
}

uint8_t proddb_rcvback(void)
{
  uint8_t ret = 0;
  FRESULT res = FR_NO_FILE;
  UINT act;
  Prod_DBFileHeaderStru fhd;

  FsDbgLog("%s\r\n", __FUNCTION__);

  /* 打开文件 若文件不存在或打开失败则退出 */
  res = f_open(&file, file_name, (FA_OPEN_EXISTING | FA_READ | FA_WRITE));
  if(res == FR_NO_FILE){
    FsDbgLog("f_open no file\r\n");
    return 2;
  }else if(res != FR_OK){
    FsErrLog("f_open res:%d\r\n", res);
    return 3;
  }

  /* 读取文件头 */
  res = f_read(&file, &fhd, sizeof(fhd), &act);
  if(res){
    FsErrLog("f_read res:%d\r\n", res);
    ret = 4;
    goto close_file3;
  }

  /* 文件头不存在或者有误 直接返回 */
  if((act < sizeof(fhd)) || (fhd.header != PROD_DBFILE_HEADER) || ((fhd.besent ^ fhd.allitm) != fhd.xorchk)){
    FsErrLog("fhd err:\r\n");
    ret = 5;
    goto close_file3;
  }

  /* 异常情况 防止误写 */
  if(fhd.besent > fhd.allitm){
    ret = 6;
    goto close_file3;
  }

  /* 防止误写 */
  if(fhd.besent == fhd.allitm){
    ret = 7;
    goto close_file3;
  }

  fhd.besent++;
  fhd.xorchk = fhd.besent ^ fhd.allitm;
  
  /* 退回至文件头 */
  res = f_rewind(&file);
  if(res || (f_tell(&file) != 0)){
    FsErrLog("f_rewind res:%d, fp:%d\r\n", res, f_tell(&file));
    ret = 8;
    goto close_file3;
  }
  
  /* 回写文件头 */
  res = f_write(&file, &fhd, sizeof(fhd), &act);
  if(res || (act != sizeof(fhd))){
    FsErrLog("f_write res:%d, btw:%d, bw:%d\r\n", res, sizeof(fhd), act);
    ret = 9;
    goto close_file3;
  }

close_file3:
  f_close(&file);

  return ret;
}
